package com.winning.pmph.service;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.winning.pmph.entity.*;
import com.winning.pmph.mapper.*;
import com.winning.pmph.utils.ApplicationContextUtil;
import com.winning.pmph.utils.ExecutorServiceFactory;
import com.winning.pmph.utils.LocalDateTimeUtil;
import com.winning.pmph.utils.PMPHAppUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jetbrains.annotations.NotNull;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
@Transactional
public class TagService extends ServiceImpl<TagMapper, Tag> {

    @Resource
    private WordsService wordsService;
    @Resource
    private CalculatorService calculatorService;
    @Resource
    private ReleasedKnowledgeService releasedKnowledgeService;
    @Resource
    private TagMapper tagMapper;
    @Resource
    private PlatformKnowledgeLibMapper platformKnowledgeLibMapper;
    @Resource
    private TempKnowledgeFieldMapper tempKnowledgeFieldMapper;
    @Resource
    private ReleasedKnowledgeFieldMapper releasedKnowledgeFieldMapper;
    @Resource
    private MedicalCalculatorFieldMapper medicalCalculatorFieldMapper;
    @Resource
    private ReleasedMedicalCalculatorFieldMapper releasedMedicalCalculatorFieldMapper;
    @Resource
    private RocketMQProducerService rocketMQProducerService;
    @Resource
    private BookService bookService;

    @Cacheable("tag")
    public ConcurrentHashMap<String, Tag> selectMap(Consumer<LambdaQueryWrapper<Tag>> consumer) {
        return lambdaQuery()
                .nested(Objects.nonNull(consumer), consumer)
                .list()
                .stream()
                .collect(Collectors.toMap(Tag::getId, Function.identity(), (a, b) -> a, ConcurrentHashMap::new));
    }

    @Cacheable("tag")
    public CopyOnWriteArrayList<Tag> selectSubTagListByTopTagId(String topTagId) {
        List<Tag> list = lambdaQuery().eq(Tag::getRootId, topTagId).gt(Tag::getLevel, 1).orderByAsc(Tag::getLevel, Tag::getIndex).list();
        return new CopyOnWriteArrayList<>(list);
    }

    @Cacheable("tag")
    public List<Tag> selectSubTagTreeByTopTagId(String topTagId) {
        List<Tag> subTagList = selectSubTagListByTopTagId(topTagId);
        // 准备 id 与tag 对应map, 便于查找;
        return prepareSubTagTree(subTagList);
    }

    @Cacheable("tag")
    public List<Tag> selectSubTagTreeByTopTagIdWithNameAndCodeAsName(String topTagId) {
        List<Tag> subTagList = selectSubTagListByTopTagId(topTagId);
        subTagList.forEach(tag -> tag.setName(tag.getName() + "(" + tag.getTagCode() + ")"));
        return prepareSubTagTree(subTagList);
    }

    @NotNull
    public List<Tag> prepareSubTagTree(List<Tag> subTagList) {
        // 准备 id 与tag 对应map, 便于查找;
        Map<String, Tag> id2TagMap = subTagList.stream().collect(Collectors.toMap(Tag::getId, tag -> tag));
        // 准备 二级标签tag集合
        List<Tag> result = subTagList.stream().filter(tag -> tag.getLevel() == 2).collect(Collectors.toList());
        for (Tag tag : subTagList) {
            if (id2TagMap.containsKey(tag.getParentId())) {
                Tag parentTag = id2TagMap.get(tag.getParentId());
                if (Objects.isNull(parentTag.getChildren())) {
                    parentTag.setChildren(Lists.newCopyOnWriteArrayList());
                }
                parentTag.getChildren().add(tag);
            }
        }
        return result;
    }

    @CacheEvict(value = "tag", allEntries=true)
    public void saveTag(Tag tag) {
        // 判断tag_code 是否修改, 如果修改, 则需要修改全部子标签;
        Tag dbTag = tagMapper.selectById(tag.getId());
        if (tag.isSelfDefinedFlag()) {
            if (Objects.nonNull(dbTag) && StringUtils.equals(tag.getTagCode(), dbTag.getTagCode())) {
                tagMapper.executeUpdate(
                        "update tag set tag_code = REPLACE(tag_code,'" + dbTag.getTagCode() + "','" + tag.getTagCode() + "'), " +
                                " updated_by = '" + PMPHAppUtil.getCurrentUserEnName() + "', " +
                                " updated_time = '" + LocalDateTimeUtil.getNowAsString() + "' " +
                                " where root_id = '" + tag.getId() + "'");
            }
        }
        tagMapper.saveBean(tag);
        if (tag.isSelfDefinedFlag()) {
            try {
                parseAndSaveSubTagFile(tag);
            } catch (IOException e) {
                log.error("解析子标签excel失败", e);
                throw new RuntimeException(e.getMessage());
            }
        }
    }

    @CacheEvict(value = "tag", allEntries=true)
    public void deleteTopTag(Tag tag) {
        tagMapper.deleteBeansByWherePart("root_id = '" + tag.getId() + "'");
        // 后续index标签, index--
        tagMapper.executeUpdate("update tag set `index` = ( `index` - 1 ), " +
                " updated_by = '" + PMPHAppUtil.getCurrentUserEnName() + "', " +
                " updated_time = '" + LocalDateTimeUtil.getNowAsString() + "' " +
                " where level = 1 and `index` > " + tag.getIndex());
    }

    @CacheEvict(value = "tag", allEntries=true)
    public void deleteSubTag(Tag tag) {
        //词库删除
        wordsService.getBaseMapper().deleteBeansByWherePart(" knowledge_id in (" +
                " WITH RECURSIVE _children AS (" +
                " SELECT * FROM tag r WHERE r.id = '" + tag.getId() + "'" +
                " UNION ALL" +
                " SELECT r.* FROM tag r,_children t WHERE t.id = r.parent_id" +
                " ) select id from _children )");
        // 删除标签及子标签;
        tagMapper.deleteBeansByWherePart("id in (" +
                " WITH RECURSIVE _children AS (" +
                " SELECT * FROM tag r WHERE r.id = '" + tag.getId() + "'" +
                " UNION ALL" +
                " SELECT r.* FROM tag r,_children t WHERE t.id = r.parent_id" +
                " ) select id from _children )");
        // 后续index标签, index--
        // 查询当前节点后续兄弟节点;
        List<Tag> nextSiblings = tagMapper.selectBeansByWherePart(
                "parent_id = '" + tag.getParentId() + "' and `index` > " + tag.getIndex() + " order by `index`");
        // 后续兄弟节点, index--
        tagMapper.executeUpdate("update tag set `index` = ( `index` - 1 ), " +
                " updated_by = '" + PMPHAppUtil.getCurrentUserEnName() + "', " +
                " updated_time = '" + LocalDateTimeUtil.getNowAsString() + "' " +
                " where parent_id = '" + tag.getParentId() + "' " +
                " and `index` > " + tag.getIndex());
        // 如果是自定义标签, 则后续tag_code需要重新计算;
        if (tag.isSelfDefinedFlag()) {
            for (Tag nextSibling : nextSiblings) {
                recursiveUpdateTagCode(nextSibling, nextSibling.getIndex() - 1);
            }
        }
        // 删除tag, 推送数据(只推动父标签, 子标签递归删除由其它平台处理);
        tag.setOption("delete");
        rocketMQProducerService.sendTag(tag.getRootId(), tag);
    }

    @CacheEvict(value = "tag", allEntries = true)
    public void subTagMoveUp(Tag tag, Tag preTag) {
        // 先修改两个标签的 index
        tag.setIndex(tag.getIndex() - 1);
        preTag.setIndex(tag.getIndex() + 1);
        tagMapper.saveBean(tag);
        tagMapper.saveBean(preTag);
        // 如果是自定义标签, 递归修改标签及子标签tag_code;
        if (tag.isSelfDefinedFlag()) {
            recursiveUpdateTagCode(tag, tag.getIndex());
            recursiveUpdateTagCode(preTag, preTag.getIndex());
        }
    }

    @CacheEvict(value = "tag", allEntries = true)
    public void topTagMoveUp(Tag tag, Tag preTag) {
        tagMapper.updateById(tag);
        tagMapper.updateById(preTag);
    }

    @CacheEvict(value = "tag", allEntries=true)
    public void recursiveTransferTag(Tag tag) {
        if (CollectionUtils.isNotEmpty(tag.getChildren())) {
            for (int i = 0; i < tag.getChildren().size(); i++) {
                Tag subTag = tag.getChildren().get(i);
                if (subTag.isTransferFlag()) {
                    // 查看supTag的id 和 subTag.parent_id 是否一致, 如果一致, 则不需要改动知识;
                    if (Objects.equals(tag.getId(), subTag.getParentId())) {
                        transferTag(tag, subTag, i);
                    }
                    // 不一致, 既要改动tag, 又要修改知识字段;
                    else {
                        transferTagAndUpdateKnowledgeReferenceField(tag, subTag, i);
                    }
                }
                // 未转移的标签, 可能排序受影响, 重新计算排序;
                else if (subTag.getIndex() != i) {
                    transferTag(tag, subTag, i);
                }
                recursiveTransferTag(subTag);
            }
        }
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void syncTopTag(String topTagId) {
        // 查找当前tag, 绑定的平台;
        List<PlatformKnowledgeLib> platformKnowledgeLibs = platformKnowledgeLibMapper.executeMultiSelect(
                "SELECT distinct pkl.PLATFORM_ID " +
                        " FROM platform_knowledge_lib pkl " +
                        " JOIN knowledge_lib_field klf ON pkl.KNOWLEDGE_LIB_ID = klf.KNOWLEDGE_LIB_ID " +
                        " WHERE klf.KIND = " + KnowledgeLibField.FIELD_KIND_REFERENCE + " AND klf.KIND_VALUE = '" + topTagId + "'");
        String username = PMPHAppUtil.getCurrentUserEnName();
        ExecutorServiceFactory.getInstance().submit(() -> syncTag(platformKnowledgeLibs, topTagId, username));
    }

    public void transferKnowledge(String selectedTagIdOri, String selectedTagId) {
        // 查询包含旧标签的知识, 稍后同步;
        List<ReleasedKnowledge> releasedKnowledges = releasedKnowledgeService.getBaseMapper().executeMultiSelect(
                " select distinct rk.*  from released_knowledge_field rkf join released_knowledge rk on rkf.KNOWLEDGE_ID = rk.id " +
                        " where rkf.property like '%" + selectedTagIdOri + "%' and rkf.kind = " + KnowledgeLibField.FIELD_KIND_REFERENCE);
        // 查询包含旧标签的知识, 稍后同步;
        List<ReleasedMedicalCalculator> releasedMedicalCalculators = calculatorService.getReleasedMedicalCalculatorSql(" select distinct rmc.* from released_medical_calculator_field rmcf join released_medical_calculator rmc on rmcf.medical_calc_id = rmc.id " +
                " where kind = 1 and property like '%" + selectedTagIdOri + "%' ");

        // 查看当前知识, 同时包含新老标签的属性, 删除旧标签;
        removeOldTagFormKnowledgeField(selectedTagIdOri, selectedTagId);
        // 转移知识属性tag;
        updateKnowledgeField(selectedTagIdOri, selectedTagId);
        // 同步知识和计算器;
        if (CollectionUtils.isEmpty(releasedKnowledges) || releasedMedicalCalculators.size() > 0) {
            String userEnName = PMPHAppUtil.getCurrentUserEnName();
            ExecutorServiceFactory.getInstance().submit(() -> syncKnowledgesAndCalculators(releasedKnowledges, releasedMedicalCalculators, userEnName));
        }
    }

    public List<Tag> queryTagByRootIdSet(Collection<String> idSet) {
        return tagMapper.selectList(Wrappers.lambdaQuery(Tag.class).select(Tag::getId, Tag::getName).in(Tag::getRootId, idSet));
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void syncSubTagByTopTagId(String topic, String tagId) {
        Tag topTag = tagMapper.selectById(tagId);
        rocketMQProducerService.sendTagToTopic(topic, topTag);
        List<Tag> allTags = selectSubTagListByTopTagId(tagId);
        allTags.forEach(tag -> rocketMQProducerService.sendTagToTopic(topic, tag));
    }

    @Cacheable("tag")
    public List<Tag> getTagByIds(String ids) {
        return tagMapper.selectBeansByWherePart("id in " + ids);
    }

    private void syncKnowledgesAndCalculators(List<ReleasedKnowledge> releasedKnowledges, List<ReleasedMedicalCalculator> releasedMedicalCalculators, String userEnName) {
        // 同步知识和计算器;
        for (ReleasedKnowledge releasedKnowledge : releasedKnowledges) {
            List<PlatformKnowledgeLib> platformKnowledgeLibs = platformKnowledgeLibMapper.selectBeansByWherePart(
                    "knowledge_lib_id = '" + releasedKnowledge.getKnowledgeLibId() + "'");
            for (PlatformKnowledgeLib platformKnowledgeLib : platformKnowledgeLibs) {
                // 发送到消息队列
                rocketMQProducerService.sendKnowledge(platformKnowledgeLib.getPlatformId(), releasedKnowledge, PMPHAppUtil.getCurrentUserEnName());
            }
        }
        // 同步计算器;
        if (releasedMedicalCalculators.size() > 0) {
            List<PlatformKnowledgeLib> platformKnowledgeLibs = platformKnowledgeLibMapper.selectBeansByWherePart("knowledge_lib_id ='" + KnowledgeLib.CALCULATOR_LIB_ID + "'");
            if (CollectionUtils.isNotEmpty(platformKnowledgeLibs)) {
                calculatorService.syncCalculator(platformKnowledgeLibs.stream().map(PlatformKnowledgeLib::getPlatformId).collect(Collectors.joining(",")),
                        releasedMedicalCalculators.stream().map(ReleasedMedicalCalculator::getId).collect(Collectors.joining(",")));
            }
        }
    }

    private void removeOldTagFormKnowledgeField(String selectedTagIdOri, String selectedTagId) {
        // 同时包含新旧标签的属性, 先删除旧标签;
        tempKnowledgeFieldMapper.executeUpdate("update temp_knowledge_field set property = REPLACE(property,'" + selectedTagIdOri + "', ',') " +
                " where property like '%" + selectedTagIdOri + "%' and property like '%" + selectedTagId + "%' and kind = " + KnowledgeLibField.FIELD_KIND_REFERENCE);
        releasedKnowledgeFieldMapper.executeUpdate("update released_knowledge_field set property = REPLACE(property,'" + selectedTagIdOri + "', ',') " +
                " where property like '%" + selectedTagIdOri + "%' and property like '%" + selectedTagId + "%' and kind = " + KnowledgeLibField.FIELD_KIND_REFERENCE);
        medicalCalculatorFieldMapper.executeUpdate("update medical_calculator_field set property = REPLACE(property,'" + selectedTagIdOri + "', ',') " +
                " where property like '%" + selectedTagIdOri + "%' and property like '%" + selectedTagId + "%' and kind = 1");
        releasedMedicalCalculatorFieldMapper.executeUpdate("update released_medical_calculator_field set property = REPLACE(property,'" + selectedTagIdOri + "', ',') " +
                " where property like '%" + selectedTagIdOri + "%' and property like '%" + selectedTagId + "%' and kind = 1");
        // 删除旧标签后, 会出现,,, [,,  ,,]等情况 删除,,
        updateKnowledgeField(",,", "");
    }

    private void updateKnowledgeField(String selectedTagIdOri, String selectedTagId) {
        tempKnowledgeFieldMapper.executeUpdate("update temp_knowledge_field set property = REPLACE(property,'" + selectedTagIdOri + "', '" + selectedTagId + "') " +
                " where kind = " + KnowledgeLibField.FIELD_KIND_REFERENCE);
        releasedKnowledgeFieldMapper.executeUpdate("update released_knowledge_field set property = REPLACE(property,'" + selectedTagIdOri + "', '" + selectedTagId + "') " +
                " where kind = " + KnowledgeLibField.FIELD_KIND_REFERENCE);
        medicalCalculatorFieldMapper.executeUpdate("update medical_calculator_field set property = REPLACE(property,'" + selectedTagIdOri + "', '" + selectedTagId + "') " +
                " where kind = 1");
        releasedMedicalCalculatorFieldMapper.executeUpdate("update released_medical_calculator_field set property = REPLACE(property,'" + selectedTagIdOri + "', '" + selectedTagId + "') " +
                " where kind = 1");
    }

    private void syncTag(List<PlatformKnowledgeLib> platformKnowledgeLibs, String topTagId, String username) {
        for (PlatformKnowledgeLib platformKnowledgeLib : platformKnowledgeLibs) {
            String platformId = platformKnowledgeLib.getPlatformId();
            List<Tag> tags = tagMapper.executeMultiSelect("select * from tag where root_id = '" + topTagId + "' order by level, `index`");
            tags.forEach(item -> rocketMQProducerService.sendTagToTopic(platformId, item));
        }
    }

    private void transferTag(Tag supTag, Tag subTag, int index) {
        subTag.setIndex(index);
        subTag.setLevel(supTag.getLevel() + 1);
        if (supTag.isSelfDefinedFlag()) {
            subTag.setTagCode(supTag.getTagCode() + "." + String.format("%03d", subTag.getIndex() + 1));
        }
        subTag.setParentId(supTag.getId());
        tagMapper.saveBean(subTag);
    }

    private void transferTagAndUpdateKnowledgeReferenceField(Tag supTag, Tag subTag, int index) {
        // 递归查找原层级关系;
        List<Tag> supTagListOri = tagMapper.executeMultiSelect("WITH RECURSIVE _parent AS ( " +
                " SELECT * FROM tag r WHERE r.id = '" + subTag.getId() + "' " +
                " UNION ALL " +
                " SELECT r.* FROM tag r, _parent p WHERE r.id = p.parent_id " +
                ") select * from _parent where level > 1 order by level");
        transferTag(supTag, subTag, index);
        // 现层级关系;
        List<Tag> supTagList = tagMapper.executeMultiSelect(
                "WITH RECURSIVE _parent AS ( " +
                        " SELECT * FROM tag r WHERE r.id = '" + subTag.getId() + "' " +
                        " UNION ALL " +
                        " SELECT r.* FROM tag r, _parent p WHERE r.id = p.parent_id " +
                        ") select * from _parent where level > 1 order by level");
        // 拼接字符串, 用于修改知识和计算器属性;
        String supTagIdsOri = supTagListOri.stream().map(Tag::getId).collect(Collectors.joining("\",\"", "\"", "\""));
        String supTagIds = supTagList.stream().map(Tag::getId).collect(Collectors.joining("\",\"", "\"", "\""));
        updateKnowledgeField(supTagIdsOri, supTagIds);
    }

    /**
     * 递归修改标签及子标签tag_code;
     *
     * @param tag
     */
    private void recursiveUpdateTagCode(Tag tag, int index) {
        String newCode = tag.getTagCode().substring(0, tag.getTagCode().length() - 3) + String.format("%03d", index + 1);
        tagMapper.executeUpdate("update tag " +
                " set tag_code = REPLACE(tag_code,'" + tag.getTagCode() + "','" + newCode + "'), " +
                "updated_by = '" + PMPHAppUtil.getCurrentUserEnName() + "', " +
                "updated_time = '" + LocalDateTimeUtil.getNowAsString() + "' " +
                " where id in ( WITH RECURSIVE _children AS ( " +
                " SELECT * FROM tag r WHERE r.id = '" + tag.getId() + "' " +
                " UNION ALL" +
                " SELECT r.* FROM tag r,_children t WHERE t.id = r.parent_id" +
                " ) select id from _children )");
    }

    private void parseAndSaveSubTagFile(Tag parentTag) throws IOException {
        File tagFileDir = new File(ApplicationContextUtil.BASE_DOWN_FORDER + "file/tag/" + parentTag.getId() + "/");
        Map<String, Tag> tagCodeMap = new HashMap<>();
        tagCodeMap.put(parentTag.getTagCode(), parentTag);
        if (tagFileDir.exists()) {
            if (tagFileDir.listFiles().length > 0) {
                // 解决parentTag下一级子标签index问题, 需要查询下一级子标签;
                List<Tag> subTagList = tagMapper.selectBeansByWherePart("parent_id = '" + parentTag.getId() + "'");
                parentTag.setChildren(Lists.newCopyOnWriteArrayList(subTagList));
            }
            for (File file : tagFileDir.listFiles()) {
                try (XSSFWorkbook workbook = new XSSFWorkbook(file)) {
                    for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                        XSSFSheet sheet = workbook.getSheetAt(i);
                        for (int j = 1; j <= sheet.getLastRowNum(); j++) {
                            XSSFRow row = sheet.getRow(j);
                            if (Objects.isNull(row)) {
                                throw new RuntimeException("文件: " + file.getName() + ", 页签: " + sheet.getSheetName() + ", 第" + (j + 1) + "行为空行");
                            }
                            Tag tag = new Tag();
                            tag.setRootId(parentTag.getRootId());
                            if (Objects.nonNull(row.getCell(0))) {
                                tag.setName(row.getCell(0).getStringCellValue());
                            }
                            if (Objects.nonNull(row.getCell(1))) {
                                tag.setOldTagCode(row.getCell(1).getStringCellValue());
                            }
                            // 如果标签名称和code都为空, 则跳过本行;
                            if (StringUtils.isBlank(tag.getName()) && StringUtils.isBlank(tag.getOldTagCode())) {
                                continue;
                            }
                            if (StringUtils.isBlank(tag.getName())) {
                                throw new RuntimeException("文件: " + file.getName() + ", 页签: " + sheet.getSheetName() + ", 第" + (j + 1) + "行, 标签名称不能为空");
                            }
                            if (StringUtils.isBlank(tag.getOldTagCode())) {
                                throw new RuntimeException("文件: " + file.getName() + ", 页签: " + sheet.getSheetName() + ", 第" + (j + 1) + "行, 标签编码不能为空");
                            }
                            if (tagCodeMap.containsKey(tag.getOldTagCode())) {
                                throw new RuntimeException("文件: " + file.getName() + ", 页签: " + sheet.getSheetName() + ", 第" + (j + 1) + "行, 标签编码重复");
                            }
                            // 计算父标签code
                            tag.setOldParentCode(tag.getOldTagCode().substring(0, tag.getOldTagCode().lastIndexOf(".")));
                            tag.setId(IdWorker.getIdStr());
                            tag.setSelfDefinedFlag(parentTag.isSelfDefinedFlag());
                            tagCodeMap.put(tag.getOldTagCode(), tag);
                            Tag cntParentTag = null;
                            if (!tagCodeMap.containsKey(tag.getOldParentCode())) {
                                throw new RuntimeException("文件: " + file.getName() + ", 页签: " + sheet.getSheetName() + ", 第" + (j + 1) + "行, 父标签编码不存在");
                            } else {
                                cntParentTag = tagCodeMap.get(tag.getOldParentCode());
                            }
                            // cntParentTag children 可能为null;
                            if (Objects.isNull(cntParentTag.getChildren())) {
                                cntParentTag.setChildren(Lists.newCopyOnWriteArrayList());
                            }
                            // 标签名称, 不能与已有标签名称重复;
                            if (cntParentTag.getChildren().stream().anyMatch(siblingTag -> Objects.equals(siblingTag.getName(), tag.getName()))) {
                                throw new RuntimeException("文件: " + file.getName() + ", 页签: " + sheet.getSheetName() + ", 第" + (j + 1) + "行, 标签名称重复");
                            }
                            tag.setParentId(cntParentTag.getId());
                            tag.setLevel(cntParentTag.getLevel() + 1);
                            tag.setIndex(cntParentTag.getChildren().size());
                            tag.setTagCode(cntParentTag.getTagCode() + "." + String.format("%03d", tag.getIndex() + 1));
                            cntParentTag.getChildren().add(tag);
                            tagMapper.insert(tag);
                        }
                    }
                } catch (Exception e) {
                    FileUtils.deleteDirectory(tagFileDir);
                    throw new RuntimeException(e.getMessage());
                }
            }
            FileUtils.deleteDirectory(tagFileDir);
        }
    }

    @Cacheable("tag")
    public List<Tag> getTagName(String name, String id) {
        List<Tag> tag = tagMapper.selectBeansByWherePart(" name in " + name + " and root_id='" + id + "' order by `level`");
        return tag;
    }

    @Cacheable("tag")
    @Transactional(propagation = Propagation.SUPPORTS)
    public List<Tag> selectTagTree() {
        // 按级别, 序号查询;
        List<Tag> tagList = lambdaQuery().list();
        // 组装成树, 返回;
        Map<String, Tag> tagMap = tagList.stream()
                .peek(tag -> tag.setName(tag.getName() + (StringUtils.isNotEmpty(tag.getTagCode()) ? "(" + tag.getTagCode() + ")" : "")))
                .collect(Collectors.toMap(Tag::getId, Function.identity()));
        List<Tag> result = tagList.stream().filter(tag -> StringUtils.isEmpty(tag.getParentId())).collect(Collectors.toList());
        for (Tag tag : tagList) {
            if (StringUtils.isNotEmpty(tag.getParentId())) {
                Tag parentTag = tagMap.get(tag.getParentId());
                if (Objects.isNull(parentTag.getChildren())) {
                    parentTag.setChildren(Lists.newCopyOnWriteArrayList());
                }
                parentTag.getChildren().add(tag);
            }
        }
        return result;
    }

    @Cacheable("tag")
    public List<Tag> selectBookCategoryCascaderOptions() {
        // 查询所有图书和分类信息;
        List<Book> bookList = bookService.lambdaQuery()
                .select(Book::getId, Book::getName, Book::getCategory).list();
        List<JSONArray> bookCategoryList = bookList.stream()
                .map(Book::getCategory)
                .filter(CollectionUtils::isNotEmpty).collect(Collectors.toList());
        // 获取所有图书分类信息;
        List<Tag> bookTagList = selectSubTagListByTopTagId(Tag.BOOK_CATEGORY_ID);
        // 遍历图书分类信息; 设置分类信息下图书数量;
        for (Tag tag : bookTagList) {
            long bookCount = bookCategoryList.stream()
                    .filter(category -> category.contains(tag.getId())).count();
            tag.setBookCount((int) bookCount);
        }
        // 过滤图书为空的分类, name 添加数量;
        bookTagList = bookTagList.stream()
                .filter(tag -> tag.getBookCount() > 0)
                .peek(tag -> tag.setName(tag.getName() + "(" + tag.getBookCount() + ")"))
                .collect(Collectors.toList());
        // 转tree返回;
        return prepareSubTagTree(bookTagList);
    }
}
